package com.example.secondhandspringboot.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.example.secondhandspringboot.constant.GoodsConstant;
import com.example.secondhandspringboot.constant.MessageConstant;
import com.example.secondhandspringboot.context.BaseContext;
import com.example.secondhandspringboot.domain.dto.GoodsDTO;
import com.example.secondhandspringboot.domain.entity.*;
import com.example.secondhandspringboot.domain.vo.GoodsVO;
import com.example.secondhandspringboot.exception.UserException;
import com.example.secondhandspringboot.mapper.GoodsMapper;
import com.example.secondhandspringboot.mapper.UserBehaviorMapper;
import com.example.secondhandspringboot.results.PageResult;
import com.example.secondhandspringboot.service.IGoodsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.secondhandspringboot.utils.IpUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 周在林
 * @since 2024-04-01
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements IGoodsService {

    private final GoodsMapper goodsMapper;
    private final UserBehaviorMapper userBehaviorMapper;

    @Override
    public PageResult<GoodsVO> getGoods(int page, int pageSize, String search) {
        //创建分页对象
        Page<GoodsVO> page1 = new Page<>(page, pageSize);
        Long userId = BaseContext.getCurrentId();
        Long schoolId = null;
        if (userId != null) {
            User user = Db.lambdaQuery(User.class).eq(User::getId, userId).one();
            schoolId = user.getSchoolId();
        }
        //分页查询
        Page<GoodsVO> pageResult;
        if (search==null || search.isEmpty()){
            pageResult = goodsMapper.getGoodsVoBySchoolId(schoolId, page1);
        }else {
            //根据用户输入进行全文检索
            pageResult = goodsMapper.searchGoods(schoolId, page1,search);
        }
        //返回数据对象
        PageResult<GoodsVO> result = new PageResult<>();
        result.setTotal(pageResult.getTotal());
        List<GoodsVO> records = pageResult.getRecords();
        // 使用Collections.shuffle()方法打乱列表顺序
        Collections.shuffle(records);
        result.setRecords(records);
        return result;
    }

    @Override
    public void pushGoods(GoodsDTO goodsDTO, HttpServletRequest request) {
        //获取当前用户id
        Long userId = BaseContext.getCurrentId();
//        Long userId = 9L;
        //封装数据
        Goods goods = BeanUtil.copyProperties(goodsDTO, Goods.class);
        //跟据用户id获取学校id
        User user = Db.lambdaQuery(User.class)
                .eq(User::getId, userId).one();
        goods.setSchoolId(user.getSchoolId());
        //获取请求ip
        String ip = request.getRemoteAddr();
//        String ip = "202.198.16.3";
        //将ip转为地理位置
        goods.setIpTerritory(IpUtil.ipReverse(ip) == null ? "未知" : IpUtil.ipReverse(ip));

        goods.setUserId(userId);
        goods.setCreateTime(LocalDateTime.now());
        goods.setUpdateTime(LocalDateTime.now());
        goodsMapper.insert(goods);
    }

    @Override
    public List<GoodsVO> getRecommendGoods() {
        return goodsMapper.getRecommendGoodsBySchoolId(null, GoodsConstant.RECOMMEND_GOODS_NUM);
    }

    @Override
    public List<GoodsVO> getGoodsHotTop(Long currentId, int hotTopGoodsNum) {
        User user = Db.lambdaQuery(User.class).eq(User::getId, currentId).one();
        Long schoolId = user==null?null:user.getSchoolId();
        return goodsMapper.getHotTopNum(schoolId,hotTopGoodsNum);
    }

    @Override
    public PageResult<GoodsVO> getMyPushGoods(int page, int pageSize, Long currentId) {
        //创建分页对象
        Page<GoodsVO> page1 = new Page<>(page,pageSize);

        Page<GoodsVO> pageResult = goodsMapper.getMyPushGoods(currentId,page1);
        PageResult<GoodsVO> pageResultVO = new PageResult<>();
        pageResultVO.setTotal(pageResult.getTotal());
        pageResultVO.setRecords(pageResult.getRecords());
        return pageResultVO;
    }

    @Override
    public List<GoodsVO> guessLike(Long currentId) {
        User user = Db.getById(currentId, User.class);
        if (user==null){
            throw new UserException(MessageConstant.USER_NOT_EXIST);
        }

        //获取学校id
        Long schoolId = user.getSchoolId();
        //创建返回对象列表
        List<GoodsVO> goodsVOList = new ArrayList<>();

        //获取所有分类,并映射到 分类权重表
        List<CategoryWeight> categoryWeightList =Db.list(Category.class).stream()
                .map(item-> new CategoryWeight(item.getId()))
                .toList();

        //统计当前用户浏览商品大于2秒的所有商品分类id和浏览次数
        List<GoodsCounted> lookGoodsCountedList = userBehaviorMapper.countLookGoodsNums(currentId,2);
        //获取当前用户所有搜索关键字,两周内的
        List<SearchKey> searchKeys = userBehaviorMapper.getSearchKey(currentId,14);

        //获取分类id以及搜索次数
        List<GoodsCounted> searchKeyCountedList = new ArrayList<>();
        searchKeys.forEach(item1->{
            List<Long> categoryIds = goodsMapper.getCategoryIdBySearchKey(item1.getSearchKeyword());
            categoryIds.forEach(item->{
                GoodsCounted goodsCounted = new GoodsCounted();
                goodsCounted.setCategoryId(item);
                goodsCounted.setNums(1);
                goodsCounted.setLastTime(item1.getTimestamp());
                searchKeyCountedList.add(goodsCounted);
            });
        });

        //合并categoryId相同的nums值，并选择lastTime最大的值
        Map<Long, GoodsCounted> groupedGoods = searchKeyCountedList.stream()
                .collect(Collectors.groupingBy(
                        GoodsCounted::getCategoryId,
                        Collectors.reducing(
                                null, // 初始化器可以是null，因为我们总是从流中的元素开始
                                (left, right) -> {
                                    if (left == null) {
                                        return right; // 第一次遇到该categoryId时直接返回right
                                    } else {
                                        return new GoodsCounted(
                                                left.getCategoryId(),
                                                left.getNums() + right.getNums(),
                                                left.getLastTime().isAfter(right.getLastTime()) ? left.getLastTime() : right.getLastTime()
                                        );
                                    }
                                }
                        )
                ));
        List<GoodsCounted> searchGoodsCountedList = new ArrayList<>(groupedGoods.values());



        //获取一周内评论商品分类id
        List<GoodsCounted> commentGoodsNums = userBehaviorMapper.countCommentNums(currentId,7);


        //浏览25%权重  评论35%  搜索40%
        lookGoodsCountedList.forEach(item->{
            Double weight = item.getNums()*0.25*(10000.0/item.getTimeDifference());
            categoryWeightList.stream()
                    .filter(cw-> Objects.equals(cw.getCategoryId(), item.getCategoryId()))
                    .findFirst()
                    .ifPresent(cw->cw.setWeight(cw.getWeight()+weight));
        });
        commentGoodsNums.forEach(item->{
            Double weight = item.getNums()*0.35*(10000.0/item.getTimeDifference());
            categoryWeightList.stream()
                    .filter(cw-> Objects.equals(cw.getCategoryId(), item.getCategoryId()))
                    .findFirst()
                    .ifPresent(cw->cw.setWeight(cw.getWeight()+weight));
        });
        searchGoodsCountedList.forEach(item->{
            Double weight = item.getNums()*0.4*(10000.0/item.getTimeDifference());
            categoryWeightList.stream()
                    .filter(cw-> Objects.equals(cw.getCategoryId(), item.getCategoryId()))
                    .findFirst()
                    .ifPresent(cw->cw.setWeight(cw.getWeight()+weight));
        });

        //按权重进行升序排序并去除weight为0的
        List<CategoryWeight> sortedCategoryWeightList = categoryWeightList.stream()
                        .filter(cw->cw.getWeight()>0)
                                .sorted((p1, p2) -> Double.compare(p2.getWeight(), p1.getWeight()))
                                        .toList();


        Random random = new Random();
        //计算总权重
        double totalWeight = sortedCategoryWeightList.stream().mapToDouble(CategoryWeight::getWeight).sum();
        int maxLoop=10;
        //随机循环获取商品
        for (int i=0;i<GoodsConstant.GUESS_LIKE_NUM;i++){

            if (maxLoop == 0) break;
            //随机生成一个值
            double randomValue = random.nextDouble() * totalWeight;
            double sum = 0;
            for (CategoryWeight categoryWeights : sortedCategoryWeightList) {
                sum += categoryWeights.getWeight();
                if (randomValue <= sum){
                    int maxLoopNum = 5; //最多查找5次，防止死循环
                    //防止随机到一样的商品
                    while (maxLoopNum != 0){
                        //跟据categoryId和schoolId获取浏览量大于30的随机一个商品
                        GoodsVO goodsVO = goodsMapper.getGoodsVoByCategoryIdAndSchoolId(categoryWeights.getCategoryId(),schoolId,30);
                        //如果为null则重新查找
                        if (goodsVO == null){
                            i--;
                            break;
                        }
                        if (!goodsVOList.contains(goodsVO)){
                            goodsVOList.add(goodsVO);
                            break;
                        }
                        maxLoopNum --;
                        //防止猜你喜欢商品个数缺少
                        if (maxLoopNum == 0){
                            i--;
                            maxLoop--;
                        }
                    }
                    break;
                }
            }
        }
        System.out.println(goodsVOList.size());
        return goodsVOList;
    }

}
